#include "atk_mw8266d.h"
#include "elog.h"
#include "smarttimer.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#if MW8266D_ENABLE

volatile uint8_t ucTcpClosedFlag = 0;

static struct{
    uint8_t rx_buf[MW8266D_UART_RX_BUF_SIZE];
    struct{
        uint16_t len:15;
        uint16_t finish:1;
    }sta;
}g_uart_rx_frame = {0};

static uint8_t g_uart_tx_buf[MW8266D_UART_TX_BUF_SIZE];

/**
****************************************************************************************
 * @description: mw8266d RST 
 * @return {*}
****************************************************************************************
*/
static void mw8266d_rst_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    GPIO_InitStructure.GPIO_Pin = MW8266D_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}

static void usart3_init(u32 bound)
{
    NVIC_InitTypeDef NVIC_InitStructure = {0};
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    USART_InitTypeDef USART_InitStructure = {0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);

    USART_DeInit(USART3);

    //TX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    //RX
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = bound;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART3, &USART_InitStructure);

    USART_Cmd(USART3, ENABLE);
    USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//enable usart receive interrupt
    USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void mw8266d_rest(void)
{
    GPIO_ResetBits(GPIOC, MW8266D_PIN);
    stim_delay(100);
    GPIO_SetBits(GPIOC, MW8266D_PIN);
    stim_delay(500);
}

static void mw8266d_uart_rx_restart(void)
{
    g_uart_rx_frame.sta.len = 0;
    g_uart_rx_frame.sta.finish = 0;
}

static void mw8266d_uart_printf(char *fmt, ...)
{
    va_list ap;
    uint16_t len;
    
    va_start(ap, fmt);
    vsprintf((char *)g_uart_tx_buf, fmt, ap);
    va_end(ap);
    
    len = strlen((const char *)g_uart_tx_buf);
    usart_send_arry(USART3, g_uart_tx_buf, len);
    log_d("where is it\r\n");
}

static uint8_t *mw8266d_uart_rx_get_frame(void)
{
    if(g_uart_rx_frame.sta.finish == 1)
    {
//        log_d("where is it\r\n");
        g_uart_rx_frame.rx_buf[g_uart_rx_frame.sta.len] = '\0';
//        log_d("%s\r\n", g_uart_rx_frame.rx_buf);
        return g_uart_rx_frame.rx_buf;
    }
    else
    {
        return NULL;
    }
}

static void mw8266d_clear_rxbuf(void)
{
    memset(g_uart_rx_frame.rx_buf, 0, sizeof(g_uart_rx_frame.rx_buf));
}

/**
****************************************************************************************
 * @description: MW8266D发送AT指令
 * @return {*}
****************************************************************************************
*/
static uint8_t mw8266d_send_AT_cmd(char *cmd, char *ack, uint32_t timeout)
{
    uint8_t *ret = NULL;

    mw8266d_uart_rx_restart();//重新开始接收新的数据包
    //mw8266d_uart_printf("%s\r\n", cmd);
//    ESP8266D_USART("%s\r\n", cmd);
//    log_d("where is it\r\n");

    if(ack == 0 || timeout == 0)
    {
        return MW8266D_EOK;
    }
    else
    {
        while(timeout--)
        {
            if(mw8266d_uart_rx_get_frame() != NULL)
            {
                if(strstr((const char *)ret, ack) != NULL)
                {
                    mw8266d_clear_rxbuf();
                    return MW8266D_EOK;
                }
                else
                {
                    log_e("error%s--%d\r\n", __FILE__, __LINE__);
                    mw8266d_uart_rx_restart();
                }
            }
            stim_delay(10);
        }
        return MW8266D_ETIMEOUT;
    }
}

/**
****************************************************************************************
 * @description: 
 * @param {char} *cmd
 * @param {char} *reply1
 * @param {char} *reply2
 * @param {uint32_t} timeout
 * @return {*}
****************************************************************************************
*/
bool fire_mw8266d_send_AT_cmd(char *cmd, char *reply1, char *reply2, uint32_t timeout)
{
    g_uart_rx_frame.sta.len = 0;//重新接收数据
    log_d("%s\r\n", cmd);

    if((reply1 == 0) && (reply2 == 0))
    {
        return 1;
    }
    stim_delay(timeout);
    g_uart_rx_frame.rx_buf[g_uart_rx_frame.sta.len] = '\0';
    log_d("%s\r\n", g_uart_rx_frame.rx_buf);

    if((reply1 != 0) && (reply2 != 0))
    {
        return (bool)strstr((const char *)g_uart_rx_frame.rx_buf, reply1) \
                 || (bool)strstr((const char *)g_uart_rx_frame.rx_buf, reply2);
    }
    else if(reply1 != 0)
    {
        return (bool)strstr((const char *)g_uart_rx_frame.rx_buf, reply1);
    }
    else
    {
        return (bool)strstr((const char *)g_uart_rx_frame.rx_buf, reply2);
    }
}

/**
****************************************************************************************
 * @description: MW8266D AT指令测试
 * @return {*}  MW8266D_EOK   : AT指令测试成功
 *              MW8266D_ERROR : AT指令测试失败
****************************************************************************************
*/
uint8_t mw8266d_AT_test(void)
{
    uint8_t ret;
    uint8_t i;

    for(i = 0; i < 10; i++)
    {
        ret = mw8266d_send_AT_cmd("AT", "OK", 500);

        if(ret == MW8266D_EOK)
        {
            return MW8266D_EOK;
        }
    }
    return MW8266D_ERROR;
}

void fire_mw8266d_AT_test(void)
{
    int i = 0;

    GPIO_SetBits(GPIOC, MW8266D_PIN);
    stim_delay(1000);

    for(i = 0; i < 10; i++)
    {
        if(fire_mw8266d_send_AT_cmd("AT", "OK", NULL, 500))
        {
            log_e("error\r\n");
            return;
        }
        mw8266d_rest();
    }

}

uint8_t mw8266d_init(u32 bound)
{
    mw8266d_rst_init();
    mw8266d_rest();
    usart3_init(bound);
    if(mw8266d_AT_test() != MW8266D_EOK)
    {
        return MW8266D_ERROR;
    }
    return MW8266D_EOK;
}

/**
****************************************************************************************
 * @description: MW8266D恢复出厂设置
 * @return {*}  MW8266D_EOK  : 恢复出场设置成功
 *              MW8266D_ERROR: 恢复出场设置失败
****************************************************************************************
*/
uint8_t mw8266d_restore(void)
{
    uint8_t ret;
    
//    log_d("where is it\r\n");
    
    ret = mw8266d_send_AT_cmd("AT+RESTORE", "ready", 3000);
    if (ret == MW8266D_EOK)
    {
        return MW8266D_EOK;
    }
    else
    {
        return MW8266D_ERROR;
    }
}

/**
****************************************************************************************
 * @description: 设置MW8266D工作模式
 * @param {uint8_t} mode    1，Station模式
 *                          2，AP模式
 *                          3，AP+Station模式
 * @return {*}
****************************************************************************************
*/
uint8_t mw8266d_set_mode(uint8_t mode)
{
    uint8_t ret;
    
    switch(mode)
    {
        case 1:
        {
            ret = mw8266d_send_AT_cmd("AT+CWMODE=1", "OK", 500);    /* Station模式 */
            break;
        }
        case 2:
        {
            ret = mw8266d_send_AT_cmd("AT+CWMODE=2", "OK", 500);    /* AP模式 */
            break;
        }
        case 3:
        {
            ret = mw8266d_send_AT_cmd("AT+CWMODE=3", "OK", 500);    /* AP+Station模式 */
            break;
        }
        default:
        {
            return MW8266D_EINVAL;
        }
    }
    
    if(ret == MW8266D_EOK)
    {
        return MW8266D_EOK;
    }
    else
    {
        return MW8266D_ERROR;
    }
}

/**
****************************************************************************************
 * @description: MW8266D软件复位
 * @return {*}MW8266D_EOK  : 软件复位成功
 *            MW8266D_ERROR: 软件复位失败
****************************************************************************************
*/
uint8_t mw8266d_sw_reset(void)
{
    uint8_t ret;
    
    ret = mw8266d_send_AT_cmd("AT+RST", "OK", 500);
    if (ret == MW8266D_EOK)
    {
        return MW8266D_EOK;
    }
    else
    {
        return MW8266D_ERROR;
    }
}

/**
****************************************************************************************
 * @description: MW8266D设置回显模式
 * @param {uint8_t} cfg 0，关闭回显
 *                      1, 打开回显
 * @return {*}
****************************************************************************************
*/
uint8_t mw8266d_ate_config(uint8_t cfg)
{
    uint8_t ret;
    
    switch(cfg)
    {
        case 0:
        {
            ret = mw8266d_send_AT_cmd("ATE0", "OK", 500);   /* 关闭回显 */
            break;
        }
        case 1:
        {
            ret = mw8266d_send_AT_cmd("ATE1", "OK", 500);   /* 打开回显 */
            break;
        }
        default:
        {
            return MW8266D_EINVAL;
        }
    }
    
    if(ret == MW8266D_EOK)
    {
        return MW8266D_EOK;
    }
    else
    {
        return MW8266D_ERROR;
    }
}

/**
****************************************************************************************
 * @description: MW8266D连接WIFI
 * @param {char} *ssid WIFI名称
 * @param {char} *pwd WIFI密码
 * @return {*}  MW8266D_EOK  : WIFI连接成功
 *              MW8266D_ERROR: WIFI连接失败
****************************************************************************************
*/
uint8_t mw8266d_join_ap(char *ssid, char *pwd)
{
    uint8_t ret;
    char cmd[64];
    
    sprintf(cmd, "AT+CWJAP=\"%s\",\"%s\"", ssid, pwd);
    ret = mw8266d_send_AT_cmd(cmd, "WIFI GOT IP", 10000);
    if (ret == MW8266D_EOK)
    {
        return MW8266D_EOK;
    }
    else
    {
        return MW8266D_ERROR;
    }
}

/**
****************************************************************************************
 * @description: MW8266D获取IP地址
 * @param {char} *buf IP地址，需要16字节内存空间
 * @return {*} MW8266D_EOK  : 获取IP地址成功
 *             MW8266D_ERROR: 获取IP地址失败
****************************************************************************************
*/
uint8_t mw8266d_get_ip(char *buf)
{
    uint8_t ret;
    char *p_start;
    char *p_end;
    
    ret = mw8266d_send_AT_cmd("AT+CIFSR", "OK", 500);
    if (ret != MW8266D_EOK)
    {
        return MW8266D_ERROR;
    }
    
    p_start = strstr((const char *)mw8266d_uart_rx_get_frame(), "\"");
    p_end = strstr(p_start + 1, "\"");
    *p_end = '\0';
    sprintf(buf, "%s", p_start + 1);
    
    return MW8266D_EOK;
}

void USART3_IRQHandler(void)
{
    u8 ret;
    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
    {
        ret = USART_ReceiveData(USART3);
        if(g_uart_rx_frame.sta.len < (MW8266D_UART_RX_BUF_SIZE - 1))
        {
            g_uart_rx_frame.rx_buf[g_uart_rx_frame.sta.len] = ret;
            g_uart_rx_frame.sta.len++;
        }
        else
        {
            g_uart_rx_frame.sta.len = 0;
            g_uart_rx_frame.rx_buf[g_uart_rx_frame.sta.len] = ret;
            g_uart_rx_frame.sta.len++;
        }
    }
    
    if(USART_GetITStatus(USART3, USART_IT_IDLE) == SET)
    {
        g_uart_rx_frame.sta.finish = 1;
        ret = USART_ReceiveData(USART3);
        ucTcpClosedFlag = strstr((const char *)g_uart_rx_frame.rx_buf, "CLOSED\r\n") ? 1 : 0;
    }
}

#endif
